use std::{sync::Arc, time::Duration};

use tauri::{Emitter, Window};
use tokio::{io::{split, AsyncReadExt, AsyncWriteExt, BufReader, WriteHalf}, sync::Semaphore};
use tokio_serial::{SerialPortBuilderExt, SerialStream};

use crate::{error::AppErr, utils::new_buf};




pub struct SerialPort {

    writer: WriteHalf<SerialStream>,
    exit_sem: Arc<Semaphore>,
}

impl SerialPort {

    pub fn new(name: &str, baud_rate: u32, window: Window) -> Result<Self, AppErr> {
        let builder = tokio_serial::new(name, baud_rate);
        let stream = builder.open_native_async()?;
        let (reader, writer) = split(stream);
        let reader = BufReader::with_capacity(512, reader);
        let exit_sem = Arc::new(Semaphore::new(0));

        tokio::spawn(read_task(reader, exit_sem.clone(), window));

        Ok(Self { writer, exit_sem })
    }

    pub fn close(&self) {
        self.exit_sem.add_permits(1);
    }

    pub async fn write(&mut self, data: &[u8]) -> Result<(), AppErr> {
        self.writer.write_all(data).await?;
        Ok(())
    } 
}

async fn read_loop<R: AsyncReadExt + Unpin>(reader: &mut R, window: Window) -> Result<(), AppErr> {

    let mut buf = new_buf(512);
    loop {
        let n = reader.read(&mut buf).await?;
        if n <= 0 {
            println!("read {}", n);
            continue;
        }
        let data = (&buf[..n]).to_vec();
        _ = window.emit("recv", data);
    }
}


async fn read_task<R: AsyncReadExt + Unpin>(mut reader: R, exit_sem: Arc<Semaphore>, window: Window) {

    tokio::select! {
        ret = read_loop(&mut reader, window) => {
            if let Err(e) = ret {
                println!("err:{}", e);
            }
        }

        _ = exit_sem.acquire() => {
            println!("read task exit");
        }
    };
    
}







